#pragma once

#include <core/types.h>
#include <core/list.h>


#define MAX_FILE_NAME_LEN   64
#define MTD_DEV_NAME_LEN    32

#define MAX_FLASH_PARTS	    16
#define DEF_VOL_ID          0  // fixme: default point to g-bios bottom half
#define BOOT_FLASH_ID       0

#define FLASH_ABSENT		0
#define FLASH_RAM			1
#define FLASH_ROM			2
#define FLASH_NORFLASH		3
#define FLASH_NANDFLASH		4
#define FLASH_DATAFLASH		6
#define FLASH_UBIVOLUME		7
#define FLASH_FLASH_PART   (1 << 6) // fixme

#define BLOCK_DEV_NAME_LEN  32

#define IS_FS_PART(type) (PT_FS_BEGIN <= (type) && (type) <= PT_FS_END)


struct Flash;

struct OobFreeRegion
{
	UINT32 nOfOffset;
	UINT32 nOfLen;
};


#define FLASH_MAX_OOBFREE_ENTRIES	8

struct NandOobLayout
{
	UINT32 nEccCodeNum;
	UINT32 piEccPos[64];

	UINT32 nFreeOobSum;
	struct OobFreeRegion mFreeRegion[FLASH_MAX_OOBFREE_ENTRIES];
};


struct EccStats
{
	UINT32 nEccCorrectCount;
	UINT32 nEccFailedCount;
	UINT32 badblocks;
	UINT32 bbtblocks;
};



typedef struct
{
	UINT32 nPageIndex;
	UINT32 nBlockIndex;
} FLASH_HOOK_PARAM;

typedef int (*FLASH_HOOK_FUNC)(struct Flash *, FLASH_HOOK_PARAM *);


#define MAX_FLASH_DEVICES  32

#define FLASH_ERASE_PENDING 0x01
#define FLASH_ERASING		0x02
#define FLASH_ERASE_SUSPEND	0x04
#define FLASH_ERASE_DONE    0x08
#define FLASH_ERASE_FAILED  0x10

#define MAX_ECC_STEPS  16

// fixme!
#define EDF_NORMAL     0
#define EDF_JFFS2      1
#define EDF_ALLOWBB    2


struct FerOpt
{
	struct Flash *pFlash;
	UINT32 dwEraseAddr;
	UINT32 dwEraseLen;
	BOOL   isForJffs2;
	BOOL   isAllowBad;
	UINT32 dwFailAddr;
	BYTE   bEraseState;
	// struct FerOpt *next;
};


typedef enum 
{
	FLASH_OOB_PLACE,
	FLASH_OOB_AUTO,
	FLASH_OOB_RAW,
	FLASH_OOB_YAFFS,  // to be removed
} OOBMODE;


struct OobOpt
{
	OOBMODE  eOpMode;
	ULONG	 dwOpLen;
	ULONG	 dwOpRetLen;
	ULONG    dwOpOobLen;
	ULONG    dwOpOobRetLen;
	UINT32   dwOpOobOff;
	BYTE    *pOpDatBuf;
	BYTE	*pOpOobBuf;
};


typedef enum
{
	PT_UNKNOWN,
	PT_BL_GBIOS,
	PT_OS_LINUX,
	PT_OS_WINCE,
	PT_FS_RAMDISK,
	PT_FS_BEGIN,
	PT_FS_CRAMFS = PT_FS_BEGIN,
	PT_FS_JFFS2,
	PT_FS_YAFFS,
	PT_FS_YAFFS2,
	// ...
	PT_FS_END = PT_FS_YAFFS2,

	PT_BAD,
	PT_FREE
} PART_TYPE;


struct ImageCache
{
	void  *pCacheBase;
	ULONG  ulCacheLen;
};

#define PART_NAME_LEN 32

struct PartAttr
{
	PART_TYPE nPartType;
	ULONG   ulPartBase;
	ULONG   ulPartSize;
	char    szPartName[PART_NAME_LEN];

	ULONG   ulBuffSize;

	char    szImgName[MAX_FILE_NAME_LEN];
	ULONG   ulImgSize;
};


struct BlockBuff
{
	ULONG     nBlkID;
	ULONG     nBuffSize;
	BYTE     *pBuffBase;
	BYTE     *pBuffPtr;
	BOOL      isValid;
};


struct Partition
{
	ULONG  ulCurPos;

	struct Flash      *pHost;
	struct PartAttr   *pAttr;
	struct ImageCache *pImgCache;	
	struct BlockBuff   mBlkBuf;

};


struct Flash
{
	int   nType;
	char  szName[BLOCK_DEV_NAME_LEN];

	union
	{
		UINT32 nWriteSize;
		UINT32 nPageSize;
	};
	union
	{
		UINT32 nEraseSize;
		UINT32 nBlockSize;
	};
	UINT32 nChipSize;

	UINT32 nWriteShift;
	UINT32 nEraseShift;
	UINT32 nChipShift;

	UINT32 nOobSize;

	struct EccStats mEccStats;

	BOOL isBadAllow;

	FLASH_HOOK_PARAM *pHookParam;
	FLASH_HOOK_FUNC   pHookFunc;

	struct Partition  vPartTab[MAX_FLASH_PARTS];
	struct PartInfo  *pPartInfo;

	int (*Read)(struct Flash *, ULONG, ULONG, ULONG *, BYTE *);
	int (*Write)(struct Flash *, ULONG, ULONG , ULONG *, const BYTE *);
	int (*Erase)(struct Flash *, struct FerOpt *);

	int (*ReadOob)(struct Flash *, ULONG, struct OobOpt *);
	int (*WriteOob)(struct Flash *,ULONG, struct OobOpt *);

	int (*BlockIsBad)(struct Flash *, ULONG);
	int (*BlockMarkBad)(struct Flash *, ULONG);
	
	int (*GetMtdName)(const struct Flash *, char []);
};


static __INLINE__ UINT32 GkFlashAllignWrite(struct Flash *pFlash, UINT32 size)
{
	return (size + pFlash->nWriteSize - 1) & ~(pFlash->nWriteSize - 1);
}

static __INLINE__ UINT32 GkFlashAllignErase(struct Flash *pFlash, UINT32 size)
{
	return (size + pFlash->nEraseSize - 1) & ~(pFlash->nEraseSize - 1);
}

int GkFlashRegister(struct Flash *pFlash);

int GkFlashUnregister(struct Flash *pFlash);

struct Flash *GkFlashGet(unsigned int num);

struct Flash *GkFlashGetEx(const char *pchName);


BOOL GuFlashGetMtdName(const struct Flash *pFlash, char szMtdName[]);

typedef enum
{
	NAND_ECC_NONE,
	NAND_ECC_SW,
//	NAND_ECC_YAFFS,
	NAND_ECC_YAFFS2,
	NAND_ECC_HW,
} ECC_MODE;


BOOL GuFlashSetEccMode(struct Flash *pFlash, ECC_MODE newMode, ECC_MODE *pOldMode);

// APIs
struct Flash *GuFlashOpen(unsigned int num);

int GuFlashClose(struct Flash *pFlash);

int GuFlashRead(struct Flash *pFlash, BYTE *buf, int *offset, int len);

int GuFlashReadRaw(struct Flash *pFlash, BYTE *buf, int *offset, int len);

long GuFlashWrite(struct Flash *pFlash, const char *buf, ULONG count, ULONG *ppos);

long GuFlashWriteRaw(struct Flash *pFlash, const char *buf, ULONG count, ULONG *ppos);

int GuFlashErase(struct Flash *pFlash, UINT32 nStartAddr, UINT32 nLen, UINT32 dwFlags);

long GuFlashWriteRaw(struct Flash *pFlash, const char *buf, ULONG count, ULONG *ppos);

struct Flash *GuFlashOpenEx(const char *name);


